package com.sky.blog.util;

import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @author sky  2022/3/26
 * @version 1.0
 */
@Component
public class SaltUtils {

    public static enum TYPE {
        /**
         * 小写字符类型
         */
        LETTER,
        /**
         * 大写字符类型
         */
        CAPITAL,
        /**
         * 数字类型
         */
        NUMBER,
        /**
         * 小写字符类型 + 大写字符类型
         */
        LETTER_CAPITAL,
        /**
         * 小写字符类型 + 数字类型
         */
        LETTER_NUMBER,
        /**
         * 大写字符类型 + 数字类型
         */
        CAPITAL_NUMBER,
        /**
         * 小写字符类型 + 大写字符类型 + 数字类型
         */
        LETTER_CAPITAL_NUMBER,
        /**
         * 其他字符类型
         */
        OTHER
    }

    private final static Map<TYPE, ArrayList<String>> DICTIONARY_CACHE = new HashMap<>();

    private final static String[] LOWERCASE = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};

    private final static String[] CAPITAL = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
            "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    private final static String[] NUMBER = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};

    private final static String[] OTHER = {"!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", ":", "|", "<", ">", "?", "-", "=", "[", "]", ";", ",", "."};

    /**
     * 随机数
     */
    private static final Random RANDOM = new Random();

    /**
     * 获取随机盐 默认长度为10 包含大小写和数字 和其它字符
     *
     * @return 随机盐
     */
    public static String getSalt() {
        return generateRandomSalt(10, TYPE.LETTER_CAPITAL_NUMBER, true);
    }

    public static String getSalt(int length) {
        return generateRandomSalt(length, TYPE.LETTER_CAPITAL_NUMBER, true);
    }

    public static String getSalt(int length, TYPE type) {
        return generateRandomSalt(length, type, true);
    }

    public static String getSalt(int length, TYPE type, boolean hasOther) {
        return generateRandomSalt(length, type, hasOther);
    }

    /**
     * @param length   获取随机串的长度
     * @param type     随机串包含的类型
     * @param hasOther 是否包含其他字符
     * @return 返回随机串
     */
    public static String generateRandomSalt(int length, TYPE type, boolean hasOther) {
        StringBuilder code = new StringBuilder();
        ArrayList<String> temp = new ArrayList<>();
        if (DICTIONARY_CACHE.containsKey(type)) {
            temp = DICTIONARY_CACHE.get(type);
        } else {
            switch (type) {
                case LETTER:
                    temp.addAll(Arrays.asList(LOWERCASE));
                    break;
                case CAPITAL:
                    temp.addAll(Arrays.asList(CAPITAL));
                    break;
                case NUMBER:
                    temp.addAll(Arrays.asList(NUMBER));
                    break;
                case LETTER_CAPITAL:
                    temp.addAll(Arrays.asList(LOWERCASE));
                    temp.addAll(Arrays.asList(CAPITAL));
                    break;
                case LETTER_NUMBER:
                    temp.addAll(Arrays.asList(LOWERCASE));
                    temp.addAll(Arrays.asList(NUMBER));
                    break;
                case CAPITAL_NUMBER:
                    temp.addAll(Arrays.asList(CAPITAL));
                    temp.addAll(Arrays.asList(NUMBER));
                    break;
                case LETTER_CAPITAL_NUMBER:
                    temp.addAll(Arrays.asList(LOWERCASE));
                    temp.addAll(Arrays.asList(CAPITAL));
                    temp.addAll(Arrays.asList(NUMBER));
                    break;
                default:
                    return getSalt();
            }
            DICTIONARY_CACHE.put(type, new ArrayList<>(temp));
        }

        if (hasOther) {
            if (DICTIONARY_CACHE.containsKey(TYPE.OTHER)) {
                temp.addAll(DICTIONARY_CACHE.get(TYPE.OTHER));
            } else {
                ArrayList<String> otherTemp = new ArrayList<>(Arrays.asList(OTHER));
                temp.addAll(otherTemp);
                DICTIONARY_CACHE.put(TYPE.OTHER, otherTemp);
            }
        }

        for (int i = 0; i < length; i++) {
            code.append(temp.get(RANDOM.nextInt(temp.size())));
        }
        return code.toString();
    }


}
